Formularios en componente padre e hijo

Descripcion

Como Implementar formularios teniendo un componente padre donde estará el manejo principal del formulario y varios componentes hijos donde tendremos implementadas las diversas partes de los inputs del formulario.

Código de ejemplo

Metodo

Antes de nada tenemos que asegurarnos de que tenemos importado el modulo ReactiveFormsModule en nuestro app.module.ts.

Componente Padre

En la clase del componente principal añadimos el siguietne código

  form = this.fb.group({});

  constructor(private fb: FormBuilder) {}

  addChildForm(name: string, group: FormGroup) {
    this.form.addControl(name, group);
  }

  onSubmit() {
    let data: Partial<formData>;
    data = this.form.value;

    console.log(data.personal?.firstName)
  }

addChildForm es la función que recoje los FormGroup que emiten los componentes hijos y que se añadirán al formulario principal, para poder manejarlos desde el componente padre.

El componente a mayores mostará la información que se introduzca en los componentes hijos al hacer submit (con la función onSubmit()), para leer la información usamos un tipo Partial que tenemos que tener tipado con la información que vamos a recibir de los formularios de los hijos, en este caso la interfaz es formData y la declaramos de la siguiente manera (normalmente en un archivo ts a parte):

interface formData {
    personal: {
        firstName: string,
        lastName: string
    }
    ,
    contact: {
        email: string
    }
} 

En el template añadimos el siguiente código:

<form [formGroup]="form" (ngSubmit)="onSubmit()">
  <app-name-form
    (formReady)="addChildForm('personal', $event)"
  ></app-name-form>
  <app-contact-form
    (formReady)="addChildForm('contact', $event)"
  ></app-contact-form>

  <div>
    <button type="submit" [disabled]="form.invalid">Submit</button>
  </div>
</form>

Este código se carga de crear los componentes hijos en los que añadiremos las partes del formulario y asociar la función addChildForm con el emitter del hijo.

Componentes Hijos

A continuacion creamos dos componentes hijo, uno que tendrá la parte del formulario para introducir el nombre y el apellido y otro que tendra la parte del formulario para introducir la información de conctacto (el e-mail).

Componente name-form.component.ts:

  @Output() formReady = new EventEmitter<FormGroup>();

  form = this.fb.group({
    firstName: ['', [Validators.required]],
    lastName: ['', [Validators.required]],
  });

  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    this.formReady.emit(this.form);
  }

Template name-form.component.html:

<h2>Personal Data</h2>
<div [formGroup]="form">
  <div>
    <label>
      Last Name
      <input formControlName="firstName" />
    </label>
  </div>
  <div>
    <label>
      First Name
      <input formControlName="lastName" />
    </label>
  </div>
</div>

Componente contact-form.component.ts:

  @Output() formReady = new EventEmitter<FormGroup>();

  form = this.fb.group({
    email: ['', [Validators.required, Validators.email]],
  });

  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    this.formReady.emit(this.form);
  }

Template contact-form.component.html:

<h2>Contact</h2>
<div [formGroup]="form">
  <div>
    <label>
      E-mail
      <input type="email" formControlName="email" />
    </label>
  </div>
</div>

Una vez tenemos todo al hacer submit deberíamos de ver en la consola el nombre que introduzcamos, si queremos acceder a los demas datos podemos hacerlo usando el objeto data (de tipo Partial<>) por ejemplo data.contact?.email

Como podemos ver en el ejemplo tambien podemos usar validaciones y hacer que el boton de submit solo se active cuando todos los campos cumplan con las validaciones indicadas

Tags

Angular | Formularios